package com.zapi.file.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zapi.file.config.FileConfig;
import com.zapi.file.entity.FileInfo;
import com.zapi.file.mapper.FileInfoMapper;
import com.zapi.file.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 文件服务实现类
 */
@Service
@Slf4j
public class FileServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> implements FileService {

    @Autowired
    private FileConfig fileConfig;

    @Override
    public FileInfo uploadFile(MultipartFile file, String path, String description, 
                             Long uploadUserId, String uploadUsername) throws Exception {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传文件不能为空");
        }

        // 检查文件大小
        long maxSize = fileConfig.getUpload().getMaxFileSize() * 1024 * 1024; // 转换为字节
        if (file.getSize() > maxSize) {
            throw new IllegalArgumentException("文件大小超过限制");
        }

        // 生成唯一文件名
        String originalFileName = file.getOriginalFilename();
        String fileExtension = getFileExtension(originalFileName);
        String fileName = IdUtil.fastSimpleUUID() + fileExtension;

        // 构建存储路径
        String storagePath = buildStoragePath(path, fileName);
        File targetFile = new File(storagePath);

        // 确保目录存在
        targetFile.getParentFile().mkdirs();

        // 保存文件
        file.transferTo(targetFile);

        // 创建文件信息
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileName(fileName);
        fileInfo.setOriginalFileName(originalFileName);
        fileInfo.setFilePath(storagePath);
        fileInfo.setFileUrl("/file/download/" + fileName);
        fileInfo.setFileSize(file.getSize());
        fileInfo.setFileType(file.getContentType());
        fileInfo.setFileExtension(fileExtension);
        fileInfo.setStorageType("LOCAL");
        fileInfo.setFileMd5(DigestUtil.md5Hex(targetFile));
        fileInfo.setStatus(1);
        fileInfo.setUploadUserId(uploadUserId);
        fileInfo.setUploadUsername(uploadUsername);
        fileInfo.setDescription(description);
        fileInfo.setCreateTime(LocalDateTime.now());
        fileInfo.setUpdateTime(LocalDateTime.now());

        // 保存到数据库
        save(fileInfo);

        log.info("文件上传成功: {}", fileName);
        return fileInfo;
    }

    @Override
    public FileInfo uploadFile(InputStream inputStream, String fileName, String path, 
                             String description, Long uploadUserId, String uploadUsername) throws Exception {
        if (inputStream == null) {
            throw new IllegalArgumentException("输入流不能为空");
        }

        // 生成唯一文件名
        String fileExtension = getFileExtension(fileName);
        String uniqueFileName = IdUtil.fastSimpleUUID() + fileExtension;

        // 构建存储路径
        String storagePath = buildStoragePath(path, uniqueFileName);
        File targetFile = new File(storagePath);

        // 确保目录存在
        targetFile.getParentFile().mkdirs();

        // 保存文件
        FileUtil.writeFromStream(inputStream, targetFile);

        // 获取文件大小
        long fileSize = targetFile.length();

        // 创建文件信息
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileName(uniqueFileName);
        fileInfo.setOriginalFileName(fileName);
        fileInfo.setFilePath(storagePath);
        fileInfo.setFileUrl("/api/file/download/" + uniqueFileName);
        fileInfo.setFileSize(fileSize);
        fileInfo.setFileType(getContentType(fileExtension));
        fileInfo.setFileExtension(fileExtension);
        fileInfo.setStorageType("LOCAL");
        fileInfo.setFileMd5(DigestUtil.md5Hex(targetFile));
        fileInfo.setStatus(1);
        fileInfo.setUploadUserId(uploadUserId);
        fileInfo.setUploadUsername(uploadUsername);
        fileInfo.setDescription(description);
        fileInfo.setCreateTime(LocalDateTime.now());
        fileInfo.setUpdateTime(LocalDateTime.now());

        // 保存到数据库
        save(fileInfo);

        log.info("文件上传成功: {}", uniqueFileName);
        return fileInfo;
    }

    @Override
    public void downloadFile(Long fileId, HttpServletResponse response) throws Exception {
        FileInfo fileInfo = getById(fileId);
        if (fileInfo == null) {
            throw new IllegalArgumentException("文件不存在");
        }

        downloadFile(fileInfo.getFilePath(), response);
    }

    @Override
    public void downloadFile(String filePath, HttpServletResponse response) throws Exception {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new IllegalArgumentException("文件不存在");
        }

        // 设置响应头
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=" + 
                URLEncoder.encode(file.getName(), "UTF-8"));
        response.setContentLength((int) file.length());

        // 写入响应流
        FileUtil.writeToStream(file, response.getOutputStream());
    }

    @Override
    public boolean deleteFile(Long fileId) throws Exception {
        FileInfo fileInfo = getById(fileId);
        if (fileInfo == null) {
            return false;
        }

        return deleteFile(fileInfo.getFilePath());
    }

    @Override
    public boolean deleteFile(String filePath) throws Exception {
        File file = new File(filePath);
        if (!file.exists()) {
            return false;
        }

        boolean deleted = file.delete();
        if (deleted) {
            log.info("文件删除成功: {}", filePath);
        }
        return deleted;
    }

    @Override
    public FileInfo copyFile(Long sourceFileId, String targetPath, String description, 
                           Long uploadUserId, String uploadUsername) throws Exception {
        FileInfo sourceFileInfo = getById(sourceFileId);
        if (sourceFileInfo == null) {
            throw new IllegalArgumentException("源文件不存在");
        }

        return copyFile(sourceFileInfo.getFilePath(), targetPath, description, uploadUserId, uploadUsername);
    }

    @Override
    public FileInfo copyFile(String sourcePath, String targetPath, String description, 
                           Long uploadUserId, String uploadUsername) throws Exception {
        File sourceFile = new File(sourcePath);
        if (!sourceFile.exists()) {
            throw new IllegalArgumentException("源文件不存在");
        }

        // 生成目标文件名
        String fileName = sourceFile.getName();
        String targetFileName = IdUtil.fastSimpleUUID() + getFileExtension(fileName);
        String fullTargetPath = buildStoragePath(targetPath, targetFileName);

        // 确保目标目录存在
        new File(fullTargetPath).getParentFile().mkdirs();

        // 复制文件
        FileUtil.copy(sourceFile, new File(fullTargetPath), true);

        // 创建新的文件信息
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileName(targetFileName);
        fileInfo.setOriginalFileName(fileName);
        fileInfo.setFilePath(fullTargetPath);
        fileInfo.setFileUrl("/api/file/download/" + targetFileName);
        fileInfo.setFileSize(sourceFile.length());
        fileInfo.setFileType(getContentType(getFileExtension(fileName)));
        fileInfo.setFileExtension(getFileExtension(fileName));
        fileInfo.setStorageType("LOCAL");
        fileInfo.setFileMd5(DigestUtil.md5Hex(new File(fullTargetPath)));
        fileInfo.setStatus(1);
        fileInfo.setUploadUserId(uploadUserId);
        fileInfo.setUploadUsername(uploadUsername);
        fileInfo.setDescription(description);
        fileInfo.setCreateTime(LocalDateTime.now());
        fileInfo.setUpdateTime(LocalDateTime.now());

        // 保存到数据库
        save(fileInfo);

        log.info("文件复制成功: {} -> {}", sourcePath, fullTargetPath);
        return fileInfo;
    }

    @Override
    public boolean moveFile(Long fileId, String targetPath) throws Exception {
        FileInfo fileInfo = getById(fileId);
        if (fileInfo == null) {
            return false;
        }

        return moveFile(fileInfo.getFilePath(), targetPath);
    }

    @Override
    public boolean moveFile(String sourcePath, String targetPath) throws Exception {
        File sourceFile = new File(sourcePath);
        if (!sourceFile.exists()) {
            return false;
        }

        // 生成目标文件名
        String fileName = sourceFile.getName();
        String targetFileName = IdUtil.fastSimpleUUID() + getFileExtension(fileName);
        String fullTargetPath = buildStoragePath(targetPath, targetFileName);

        // 确保目标目录存在
        new File(fullTargetPath).getParentFile().mkdirs();

        // 移动文件
        boolean moved = sourceFile.renameTo(new File(fullTargetPath));
        if (moved) {
            log.info("文件移动成功: {} -> {}", sourcePath, fullTargetPath);
        }
        return moved;
    }

    @Override
    public Page<FileInfo> getFileList(Integer current, Integer size, String fileName, 
                                    String fileType, String storageType, Long uploadUserId) {
        Page<FileInfo> page = new Page<>(current, size);
        QueryWrapper<FileInfo> queryWrapper = new QueryWrapper<>();

        if (StrUtil.isNotBlank(fileName)) {
            queryWrapper.like("file_name", fileName);
        }
        if (StrUtil.isNotBlank(fileType)) {
            queryWrapper.eq("file_type", fileType);
        }
        if (StrUtil.isNotBlank(storageType)) {
            queryWrapper.eq("storage_type", storageType);
        }
        if (uploadUserId != null) {
            queryWrapper.eq("upload_user_id", uploadUserId);
        }

        queryWrapper.orderByDesc("create_time");

        return page(page, queryWrapper);
    }

    @Override
    public List<String> listFiles(String path) throws Exception {
        File directory = new File(buildStoragePath(path, ""));
        if (!directory.exists() || !directory.isDirectory()) {
            throw new IllegalArgumentException("目录不存在");
        }

        File[] files = directory.listFiles();
        if (files == null) {
            return new ArrayList<>();
        }

        List<String> fileNames = new ArrayList<>();
        for (File file : files) {
            fileNames.add(file.getName());
        }
        return fileNames;
    }

    @Override
    public boolean createDirectory(String path) throws Exception {
        File directory = new File(buildStoragePath(path, ""));
        if (directory.exists()) {
            return directory.isDirectory();
        }

        boolean created = directory.mkdirs();
        if (created) {
            log.info("目录创建成功: {}", path);
        }
        return created;
    }

    @Override
    public FileInfo getFileInfo(Long fileId) {
        return getById(fileId);
    }

    @Override
    public FileInfo getFileInfoByPath(String filePath) {
        QueryWrapper<FileInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("file_path", filePath);
        return getOne(queryWrapper);
    }

    @Override
    public boolean exists(String filePath) throws Exception {
        return new File(filePath).exists();
    }

    @Override
    public long getFileSize(String filePath) throws Exception {
        File file = new File(filePath);
        if (!file.exists()) {
            throw new IllegalArgumentException("文件不存在");
        }
        return file.length();
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        if (StrUtil.isBlank(fileName)) {
            return "";
        }
        int lastDotIndex = fileName.lastIndexOf('.');
        return lastDotIndex > 0 ? fileName.substring(lastDotIndex) : "";
    }

    /**
     * 根据扩展名获取Content-Type
     */
    private String getContentType(String extension) {
        if (StrUtil.isBlank(extension)) {
            return "application/octet-stream";
        }

        String ext = extension.toLowerCase();
        switch (ext) {
            case ".jpg":
            case ".jpeg":
                return "image/jpeg";
            case ".png":
                return "image/png";
            case ".gif":
                return "image/gif";
            case ".pdf":
                return "application/pdf";
            case ".doc":
                return "application/msword";
            case ".docx":
                return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
            case ".xls":
                return "application/vnd.ms-excel";
            case ".xlsx":
                return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            case ".txt":
                return "text/plain";
            default:
                return "application/octet-stream";
        }
    }

    /**
     * 构建存储路径
     */
    private String buildStoragePath(String path, String fileName) {
        String basePath = fileConfig.getLocal().getRootPath();
        if (StrUtil.isNotBlank(path)) {
            basePath = basePath + "/" + path;
        }
        return basePath + "/" + fileName;
    }
} 